<template>
  <div class="department-container">
    <div class="app-container">
      <!-- tabs 标签页组件 -->
      <el-tabs v-model="activeName">
        <!-- 角色管理 -->
        <el-tab-pane label="角色管理" name="first">
          <!-- 按钮 -->
          <div class="btn-warp">
            <el-button type="primary" size="small" @click="addRoleBtn">新增角色</el-button>
          </div>
          <!-- table 表格 -->
          <div>
            <el-table
              :data="tableData"
              border
              :stripe="true"
              style="width: 100%"
            >
              <el-table-column
                type="index"
                label="序号"
                width="50"
              />
              <el-table-column
                prop="name"
                label="角色"
                width="100"
              />
              <el-table-column
                prop="description"
                label="描述"
              />
              <el-table-column
                prop="right"
                label="操作"
                width="284"
              >
                <!-- 这里使用 作用域插槽:  -->
                <!-- 可以通过 v-slot="属性名" 的方式, 可以获取到我们当前点击的当前项的对应的数据 --> -->
                <template v-slot="scoped">
                  <el-button type="primary" size="mini" plain @click="assignPermissionBtn(scoped.row.id)">分配权限</el-button>
                  <el-button type="success" size="mini" plain @click="editRoleBtn(scoped)">编辑</el-button>
                  <el-button type="danger" size="mini" plain @click="deleteBtn(scoped.row.id)">删除</el-button>
                </template>
              </el-table-column>
            </el-table>
          </div>
          <!-- 分页 -->
          <div class="pagin-warp">
            <el-pagination
              :current-page.sync="form.page"
              :page-sizes="[10, 20, 30, 40]"
              :page-size="form.pageSize"
              layout="total, prev, pager, next, sizes"
              :total="total"
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
            />
          </div>
        </el-tab-pane>
        <el-tab-pane label="配置管理" name="second">配置管理</el-tab-pane>
        <el-tab-pane label="角色管理" name="third">角色管理</el-tab-pane>
        <el-tab-pane label="定时任务补偿" name="fourth">定时任务补偿</el-tab-pane>
      </el-tabs>
    </div>

    <!-- 添加/编辑角色 对话框 -->
    <el-dialog
      :title="isEdit ? '编辑角色' : '新增角色'"
      :visible.sync="dialogVisible"
      width="50%"
      @close="dialogCloseBtn"
    >
      <el-form ref="formRef" :model="formDialog" :rules="rules" label-width="80px">
        <el-form-item label="角色名称" prop="name">
          <el-input v-model="formDialog.name" />
        </el-form-item>
        <el-form-item label="角色描述" prop="description">
          <el-input v-model="formDialog.description" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onSubmit">{{ isEdit ? '立即编辑' : '立即创建' }}</el-button>
          <el-button @click="dialogVisible = false">取消</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>

    <!-- 分配权限 弹出框 -->
    <el-dialog
      title="分配权限"
      :visible.sync="dialogPermissionVisible"
      width="50%"
      :show-close="false"
      :close-on-press-escape="false"
      :close-on-click-modal="false"
    >
      <!-- 导入自己封装的组件 完成分配权限模块 -->
      <!-- 父传子: 将当前点击的角色的 id currentId 传给子组件 -->
      <assign-permission
        v-if="dialogPermissionVisible"
        :current-id="currentId"
        @close="dialogPermissionVisible = false"
      />
    </el-dialog>

  </div>
</template>

<script>
import { addRolesRequest, getRolesListRequest, editRolesRequest, deleteRolesRequest } from '@/api/setting'
import _ from 'lodash'
import AssignPermission from './AssignPermission.vue'
export default {
  name: 'SettingsCom',
  components: { AssignPermission },
  props: {
    aaa: {
      default: 66,
      type: Number
    }
  },
  data() {
    return {
      activeName: 'first',
      // 由于父向子传值, 子组件不能修改父组件的数据
      // 假设我们要修改这个值, 就要将 props 中接受的数据, 赋值给当前组件 data 中的私有数据
      // 我们可以修改我们当前组件中的 data 数据, 然后再去通知父组件修改自己的数据
      // 所以我们可以在 变量初始化时, 直接将初始值设置为 props 中接收到的父组件数据
      test: this.aaa,
      tableData: [],
      // 定义校验规则
      rules: {
        name: [
          { required: true, message: '请输入角色名称', trigger: 'blur' }
        ],
        description: [
          { required: true, message: '请输入角色描述', trigger: 'blur' }
        ]
      },
      // 分页数据
      form: {
        page: 1,
        pageSize: 10 // 每页显示多少条数据
      },
      // 控制新增角色 对话框 显示隐藏
      dialogVisible: false,
      // 控制分配权限模态框显示隐藏
      dialogPermissionVisible: false,
      // 新增角色 - 表单数据初始化
      formDialog: {
        name: '',
        description: ''
      },
      // 页码
      total: 0,
      // 判断是否为编辑
      isEdit: false,
      // 当前点击的角色对应的 id
      currentId: ''
    }
  },
  computed: {
    // 最大页码值
    maxPageNum() {
      return Math.ceil(this.total / this.form.pageSize)
    },
    // 判断最后一页是否填满: 如果不等于0, 代表没填满返回 false
    isLastPageFull() {
      return this.total % this.form.pageSize === 0
    }
  },
  created() {
    // 获取列表渲染页面
    this.getRolesList()
  },
  methods: {
    // ^ ================ 定义函数发送 ajax 请求 ================
    // 发送请求 - 获取所有角色列表
    async getRolesList() {
      try {
        const res = await getRolesListRequest(this.form)
        // 业务代码成功条件
        if (res.success) {
          this.tableData = res.data.rows
          this.total = res.data.total
        } else {
          this.$message.error(res.message)
        }
      } catch (error) {
        console.log('获取所有角色列表失败', error)
      }
    },
    // 发送请求 - 添加角色
    async addRoles() {
      try {
        const res = await addRolesRequest(this.formDialog)
        // 业务代码成功后的操作
        if (res.success) {
          this.$message.success('添加角色成功')
          this.success()
          console.log(res)
          // 添加成功以后, 应该立刻跳转到最后一页
          // 判断: 如果 为true 代表最后一页被填满了, 就将当前页 设置为最大页码数加一, 并让总页数自增
          // 如果 为false 代表最后一个没有被填满, 那么就让当前的页码赋值为最大页码值
          if (this.isLastPageFull) { // 没填满, 让当前页码为最大页码 + 1
            this.page = this.maxPageNum + 1
            this.total++
          } else { // 填满了, 让当前页码为最大页码
            this.form.page = this.maxPageNum
          }
        } else {
          this.$message.error(res.message)
        }
      } catch (error) {
        console.log('添加角色失败', error)
        this.$message.error('添加角色失败')
      }
    },
    // 发送请求 - 编辑角色 / 更新角色
    async editRoles() {
      try {
        const res = await editRolesRequest(this.formDialog)
        console.log(res)
        this.success() // 编辑程功, 调用 success 函数, 关闭弹窗, 渲染页面
      } catch (error) {
        console.log('编辑角色失败', error)
      }
    },
    // 发送请求 - 根据 id 删除角色
    async deleteRoles(id) {
      try {
        const res = await deleteRolesRequest(id)
        // 业务代码成功后, 提示用户
        if (res.success) {
          this.$message({
            type: 'success',
            message: '删除成功!'
          })
          // 删除成功后, 当前页码值怎么调整
          // 如果当前页面只剩一条数据, 那么在删掉当前页面最后一条数据后, 应该回到前一页
          // 所以需要将 page - 1
          if (this.tableData.length === 1) {
            this.form.page--
            if (this.form.page <= 0) this.form.page = 1
          }
          this.getRolesList() // 获取列表, 渲染页面
        } else {
          this.$message({
            type: 'info',
            message: '删除请求失败'
          })
        }
      } catch (error) {
        console.log('删除角色失败', error)
      }
    },
    // ^ ================ 定义事件处理函数 ================
    // 分页页码 - 点击事件处理函数
    handleSizeChange(value) {
      // 每页显示条数的改变
      this.form.page = 1
      this.form.pagesize = value
      this.getRolesList()
    },
    // 分页左右切换箭头 - 事件处理函数
    handleCurrentChange(value) {
      // 页码值的改变
      this.form.page = value
      this.getRolesList()
    },
    // 提交按钮 - 提交表单事件处理函数
    // 判断是否为编辑, 如果是, 就发送编辑请求, 如果不是, 就发送添加请求
    // 兜底校验, 如果校验通过, 就调用函数发送请求
    onSubmit() {
      this.$refs.formRef.validate(val => {
        if (val) this.isEdit ? this.editRoles() : this.addRoles()
      })
    },
    // 成功事件 - 处理弹窗, 重新渲染页面
    success() {
      this.dialogVisible = false
      this.getRolesList() // 获取列表, 渲染页面
    },
    // 新增角色 - 事件处理函数
    addRoleBtn() {
      this.dialogVisible = true // 开启对话框
      this.isEdit = false // 是否为编辑: 否
    },
    // 编辑按钮 - 事件处理函数
    editRoleBtn(value) {
      this.dialogVisible = true // 打开弹出框
      this.isEdit = true // 是否为编辑: 是
      // 数据回显, 将点击的当前项的数据, 赋值给 form 表单数据
      // 这里不能使用直接赋值的方式 将请求的数据赋给表单数据
      // 因为引用数据类型直接赋值是给的地址, 这样修改数据时, 二者数据会同步变化
      // 所以这里可以通过深拷贝来实现 (深拷贝三种方法: 转JSON字符串, lodash库, 递归函数)
      this.formDialog = _.cloneDeep(value.row)
    },
    // 删除按钮事件处理函数
    deleteBtn(id) { // 点击删除按钮, 将 scoped.row.id 传给事件处理函数
      this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.deleteRoles(id) // 调用请求函数, 将 id 传给请求函数
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消删除'
        })
      })
    },
    // 取消按钮 - 事件
    dialogCloseBtn() {
      this.$refs.formRef.resetFields() // 调用 resetFields() 方法重置表单数据
      if (this.isEdit) {
        // this.$options 方法详解:
        // this.$options 包含了当前组件实例初始化时所有的数据
        // this.$options 就是当前这个组件 new  VueComponent() 创建的时候的 所有值的初始值情况
        // 通过 options 调用 data() 函数, 可以将所有数据初始化一个新的地址, 可以用来进行数据初始化
        // 利用 options对象, 将 data()数据 formDialog 初始化
        this.formDialog = this.$options.data().formDialog
        // 如果 data() 函数中的变量, 使用了this, 出现了 this 改变的情况, 就需要使用到如下方法
        // 通过 call 方法调用 data函数 并改变 this 指向, 让 this 重新指回当前的 vue 组件实例
        // 这样就不会导致 data 数据中 this 指向混乱的问题
        // teacher:
        // 如果在 data 里面, 使用了 this 获取一些数据的初始值
        // 那么如果我们直接用 this.$options.data() 调用的时候, 当前 data 里面的 this 就会指向其他地方
        // 但是正常代码里面 this 是必须指向当前组件实例的, 所以需要我们手动指定 this 值为当前的组件实例
        // this.formDialog = this.$options.data.call(this).formDialog
      }
    },
    // 事件 - 分配权限按钮点击事件
    assignPermissionBtn(id) {
      this.dialogPermissionVisible = true // 打开模态框
      // 形参获取到当前点击的角色的 id, 将其赋值给变量 currentId, 并进行父传子传给子组件
      this.currentId = id
    }
  }

}
</script>

<style lang="scss" scoped>
.app-container {
  border: 3px solid #e4e7ed;
  ::v-deep .btn-warp {
    margin: 15px 0;
  }
  .pagin-warp {
    margin-top: 15px;
    text-align: center;
  }
}
</style>
